package com.ts.common.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.alibaba.fastjson.JSONObject;
import com.ts.animal.constant.AnimalConstant;
import com.ts.common.config.TsConfig;
import com.ts.common.constant.CommonConstant;
import com.ts.common.service.ExportExcelSevice;
import com.ts.system.util.SystemUtil;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Excel操作类
 *
 * @author jolley
 */
public class UtilEasyExcel {

    private static Logger log = LoggerFactory.getLogger(UtilEasyExcel.class);
    Map<String, Object> params;
    List<?> dataset;
    ExportExcelSevice deVal;

    String fileName;
    String filePath;
    String[] headArr;
    String[] keyArr;
    List<List<String>> headList = new ArrayList<List<String>>();
    List<List<Object>> dataList = new ArrayList<List<Object>>();
    boolean lowerUnderscore = false;


    public UtilEasyExcel(Map<String, Object> params, List<?> dataset) {
        init(params, dataset, null, false);
    }

    public UtilEasyExcel(Map<String, Object> params, List<?> dataset, ExportExcelSevice deVal) {
        init(params, dataset, deVal, false);
    }

    public UtilEasyExcel(Map<String, Object> params, List<?> dataset, ExportExcelSevice deVal, boolean lowerUnderscore) {
        init(params, dataset, deVal, lowerUnderscore);
    }

    /**
     * @param params          导出数据信息-如表头、文件名称、数据字段名称等
     * @param dataset         导出数据结果集
     * @param deVal           格式化数据接口
     * @param lowerUnderscore 数据转化时，属性字段名称匹配时是否需要从_转为驼峰
     */
    private void init(Map<String, Object> params, List<?> dataset, ExportExcelSevice deVal, boolean lowerUnderscore) {
        this.params = params;
        this.dataset = dataset;
        this.deVal = deVal;
        this.lowerUnderscore = lowerUnderscore;

        String exportSplit = (String) params.get(CommonConstant.EXPORT_SPLIT_FLAG);
        if (StringUtils.isEmpty(exportSplit)) {
            return;
        }

        fileName = (String) params.get(CommonConstant.EXPORT_FILENAME_FLAG);
        if (StringUtils.isEmpty(fileName)) {
            fileName = "导出数据";
        }

        String headers = (String) params.get(CommonConstant.EXPORT_HEADER_FLAG);
        headArr = null;
        if (StringUtils.isEmpty(headers)) {
            return;
        } else {
            headArr = headers.split(exportSplit);
        }

        String keys = (String) params.get(CommonConstant.EXPORT_KEYS_FLAG);
        keyArr = null;
        if (StringUtils.isEmpty(keys)) {
            return;
        } else {
            keyArr = keys.split(exportSplit);
        }

        String sys_save_path = TsConfig.getProperty("ts.downPath");
        String savePath = sys_save_path + UtilExportFileName.getName();
        //测试地址
        File fileDic = new File(savePath);
        if (!fileDic.exists()) {
            // 无此文件夹时创建
            fileDic.mkdirs();
            //设置权限
            fileDic.getParentFile().setReadable(true);
            fileDic.getParentFile().setExecutable(true);
            fileDic.setReadable(true);
            fileDic.setExecutable(true);
        }
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
        String now = df.format(new Date());
        // 文件保存的名字
        fileName = fileName + now + ".xls";
        // 保存的文件路径
        filePath = savePath + fileName;

        for (int i = 0; i < headArr.length; i++) {
            List<String> head = new ArrayList<String>();
            head.add(headArr[i]);
            headList.add(head);
        }

        for (int k = 0; k < dataset.size(); k++) {
            dataList.add(new ArrayList<>());
            Object obj = dataset.get(k);
            JSONObject jsonObj = JSONObject.parseObject(JSONObject.toJSONString(obj));
            if (lowerUnderscore) {
                jsonObj = CaseFormatUtil.lowerUnderscore(jsonObj);
            }
            for (int i = 0; i < keyArr.length; i++) {
                Object value = jsonObj.get(keyArr[i]);
                if (this.deVal != null && value != null && !UtilString.isEmpty(value)) {
                    value = deVal.changeVal(keyArr[i], value, jsonObj);
                    dataList.get(k).add(value);
                } else {
                    dataList.get(k).add(value);
                }
            }
        }
        // 保存文件
    }

    public void dynamicWrite() {
        // 头的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 背景设置为红色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 12);
        headWriteCellStyle.setWriteFont(headWriteFont);
        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
        contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
        // 背景绿色
        contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
        WriteFont contentWriteFont = new WriteFont();
        // 字体大小
        contentWriteFont.setFontHeightInPoints((short) 12);
        contentWriteCellStyle.setWriteFont(contentWriteFont);
        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);


        log.info("导出文件路径：{}", filePath);
        // 数据量大，每个sheet 6w条数据
        int pageSize = Integer.valueOf(SystemUtil.getSystemParams().get(AnimalConstant.key_name_export_sheetSize).getParamValue());
        int total = this.dataList.size();
        int page = (total / pageSize) + ((total % pageSize > 0) ? 1 : 0);
        try (ExcelWriter excelWriter = EasyExcel.write(filePath)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .registerWriteHandler(horizontalCellStyleStrategy)
                .build()) {
            for (int i = 0; i < page; i++) {
                int endNum = 0;
                if (i == page - 1) {
                    endNum = total;
                } else {
                    endNum = pageSize * (i + 1);
                }
                List<List<Object>> sub = dataList.subList(pageSize * i, endNum);
                WriteSheet writeSheet = EasyExcel.writerSheet(i, "数据" + (i + 1)).head(this.headList).build();
                excelWriter.write(sub, writeSheet);
            }
        }
        log.info("导出数据完成，路径：{}", filePath);

    }

    public Map<String, Object> getParams() {
        return params;
    }

    public void setParams(Map<String, Object> params) {
        this.params = params;
    }

    public List<?> getDataset() {
        return dataset;
    }

    public void setDataset(List<?> dataset) {
        this.dataset = dataset;
    }

    public ExportExcelSevice getDeVal() {
        return deVal;
    }

    public void setDeVal(ExportExcelSevice deVal) {
        this.deVal = deVal;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

    public String getFilePath() {
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    public String[] getHeadArr() {
        return headArr;
    }

    public void setHeadArr(String[] headArr) {
        this.headArr = headArr;
    }

    public String[] getKeyArr() {
        return keyArr;
    }

    public void setKeyArr(String[] keyArr) {
        this.keyArr = keyArr;
    }

    public List<List<String>> getHeadList() {
        return headList;
    }

    public void setHeadList(List<List<String>> headList) {
        this.headList = headList;
    }

    public List<List<Object>> getDataList() {
        return dataList;
    }

    public void setDataList(List<List<Object>> dataList) {
        this.dataList = dataList;
    }

    public boolean isLowerUnderscore() {
        return lowerUnderscore;
    }

    public void setLowerUnderscore(boolean lowerUnderscore) {
        this.lowerUnderscore = lowerUnderscore;
    }

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
        int pageSize = 3;
        int total = list.size();
        int page = (total / pageSize) + ((total % pageSize > 0) ? 1 : 0);
        System.out.println(pageSize);
        System.out.println(total);
        System.out.println(page);
        for (int i = 0; i < page; i++) {
            int endNum = 0;
            if (i == page - 1) {
                endNum = total;
            } else {
                endNum = pageSize * (i + 1);
            }
            List<Integer> sub = list.subList(pageSize * i, endNum);
            System.out.println(JSONObject.toJSONString(sub));
        }
    }

}
